/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/
import {
  BaseCommand,
  CMEVENTS,
  pickedFaceData,
  pickedLineData,
  pickedVertexData,
} from '@amcax/base';
import { eventCenterManager } from '@app-base/common/events/EventCenterManager';
import {
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-cad/common/components/command-form/constants';
import { PickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { MessageTip } from '@app-cad/common/utils/MessageTip';
import { previewer, userEvents } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import { FeaturedCmdDialogParams } from '@app-cad/types';
import { RJSFSchema } from '@rjsf/utils';
import { useAsyncEffect } from 'ahooks';
import i18n from 'i18next';
import { omitBy } from 'lodash';
import { useEffect, useMemo, useState } from 'react';
import { useSwitchVisibility } from '../common/hooks/useSwitchVisibility';
import './index.scss';

type PickData = Array<(pickedLineData & pickedFaceData) & pickedVertexData>;

type FormData = {
  chamferType: string;
  type?: string;
  pickData?: PickData;
  distance?: number;
  angle?: number;
  distance1?: number;
  distance2?: number;
};
type Params = {
  type?: string;
  mode: string;
  base: string;
  faces?: Array<object>;
  vertices?: Array<object>;
  edges?: Array<object>;
};

// 倒角
function ChamferDialog({ title, onClose, props }: FeaturedCmdDialogParams) {
  const { picker } = useTools();
  const [formData, setFormData] = useState<FormData>({
    chamferType: 'angle',
    distance: 2,
    distance1: 2,
    distance2: 2,
    angle: 45,
  });

  useSwitchVisibility(props?.params?.base, props?.shape);

  useEffect(() => {
    previewAction();
  }, [formData]);

  useEffect(() => {
    eventCenterManager.activeEventCenter.setState('chamfer').addExit(exit);
    // 注册原始模型删除事件
    userEvents.on(CMEVENTS.MODEL_ADDED, newModelAdded);
    return exit;
  }, []);
  //验证formdata值改变的时候是否触发api
  const validataFormData = () => {
    if (formData?.pickData?.length > 0) {
      // 输入值
      if (
        (formData.chamferType === 'angle' &&
          formData.angle &&
          formData.distance > 0) ||
        (formData.chamferType === 'distance' &&
          formData.distance1 > 0 &&
          formData.distance2 > 0) ||
        (formData.chamferType === 'symmetry' && formData.distance > 0)
      ) {
        return true;
      }
    }
    return false;
  };
  const finishValid = useMemo(validataFormData, [formData]);
  // 从formdata中获取api获取得参数
  const getParams = () => {
    const params: Params = {
      type: formData.chamferType,
      mode: 'dis-dis',
      base: props == null ? formData.pickData[0].idInfo.o : props.params.base,
      faces: [],
      edges: [],
      vertices: [],
    };
    let r1, r2;
    if (formData.chamferType === 'angle') {
      r1 = formData.distance;
      r2 = formData.angle;
      params.mode = 'dis-angle';
    } else if (formData.chamferType === 'distance') {
      r1 = formData.distance1;
      r2 = formData.distance2;
    } else if (formData.chamferType === 'symmetry') {
      r1 = formData.distance;
      r2 = formData.distance;
    }
    formData.pickData.forEach((item) => {
      if (item.meshId) {
        params.faces.push({
          id: item.idInfo?.i,
          r1,
          r2,
        });
      }
      if (item.edgeId) {
        params.edges.push({
          id: item.idInfo?.i,
          r1,
          r2,
        });
      }
      if (item.vertexId) {
        params.vertices.push({
          id: item.idInfo?.i,
          r1,
          r2,
        });
      }
    });
    return params;
  };
  // 判断选择的面是否在同一个体上
  const isSameShell = (planes: PickData) => {
    const shellSet = new Set();
    for (let i = 0; i < planes.length; i++) {
      const modelDxid = planes[i].idInfo.o;
      shellSet.add(modelDxid);
    }
    return shellSet.size === 1;
  };
  useAsyncEffect(async () => {
    if (props == null) {
      return;
    }
    const { edges, faces, vertices, type } = props.params;
    const baseId = props.baseid;
    let distance, angle, distance1, distance2, dataObj;
    if (edges?.length > 0) {
      distance1 = distance = edges[0].r1;
      distance2 = angle = edges[0].r2;
      for (const item of edges) {
        await initEditDependency([`${baseId}:e${item.id}`]);
      }
      dataObj = edges.map(
        (item) =>
          picker.generatePickObjByPickID(
            `${baseId}:e${item.id}`,
          ) as pickedLineData,
      );
    }
    if (faces?.length > 0) {
      distance1 = distance = faces[0].r1;
      distance2 = angle = faces[0].r2;
      for (const item of faces) {
        await initEditDependency([`${baseId}:f${item.id}`]);
      }
      dataObj = faces.map(
        (item) =>
          picker.generatePickObjByPickID(
            `${baseId}:f${item.id}`,
          ) as pickedFaceData,
      );
    }
    if (vertices?.length > 0) {
      distance1 = distance = vertices[0].r1;
      distance2 = angle = vertices[0].r2;
      for (const item of vertices) {
        await initEditDependency([`${baseId}:v${item.id}`]);
      }
      dataObj = vertices.map(
        (item) =>
          picker.generatePickObjByPickID(
            `${baseId}:v${item.id}`,
          ) as pickedVertexData,
      );
    }
    setFormData({
      chamferType: type,
      pickData: dataObj,
      angle,
      distance,
      distance1,
      distance2,
    });
  }, []);
  // 添加成功
  const newModelAdded = () => {
    onClose();
  };

  // 执行
  const handleExecute = async () => {
    if (props == null) {
      wsApi.createChamfer(getParams(), false);
    } else {
      wsApi.setParams(props.shape, getParams());
    }
  };

  const exit = () => {
    eventCenterManager.activeEventCenter.setDefault();
    userEvents.off(CMEVENTS.MODEL_ADDED, newModelAdded);
  };
  const schema: RJSFSchema = useMemo(() => {
    // omitBy,处理属性值为null
    const properties = omitBy(
      {
        pickData: {
          type: 'array',
          items: {
            type: 'string',
            enum: [],
          },
          uniqueItems: true,
          title: '请选择点/线/面',
          format: PickInputRJSFFormat.MultiPickALL,
        },
        chamferType: {
          title: '角度类型',
          type: 'string',
          oneOf: [
            {
              type: 'string',
              title: '角度距离',
              const: 'angle',
            },
            {
              type: 'string',
              title: '距离距离',
              const: 'distance',
            },
            {
              type: 'string',
              title: '对称',
              const: 'symmetry',
            },
          ],
          default: 'angle',
        },
        angle:
          formData.chamferType === 'angle'
            ? {
                title: '角度',
                type: 'number',
                minimum: 0.01,
                format: NumberInputFormat.Angle,
              }
            : null,
        distance:
          formData.chamferType === 'angle' ||
          formData.chamferType === 'symmetry'
            ? {
                title: '距离',
                type: 'number',
                minimum: 0.01,
                format: NumberInputFormat.Length,
              }
            : null,
        distance1:
          formData.chamferType === 'distance'
            ? {
                title: '距离1',
                type: 'number',
                minimum: 0.01,
                format: NumberInputFormat.Length,
              }
            : null,
        distance2:
          formData.chamferType === 'distance'
            ? {
                title: '距离2',
                type: 'number',
                minimum: 0.01,
                format: NumberInputFormat.Length,
              }
            : null,
      },
      (val) => val == null,
    );
    return {
      type: 'object',
      properties,
    } as RJSFSchema;
  }, [formData.chamferType]);
  const checkAndFinishDraw = async () => {
    if (validataFormData()) {
      handleExecute();
      previewer.clear();
      onClose();
    }
  };
  const { initEditDependency, initingEdit, previewInCommand } = useCommand(
    'cmd-shell',
    {
      onClose,
      finishDraw: checkAndFinishDraw,
    },
  );
  const execute = async (preview) => {
    const isSame = isSameShell(formData.pickData);
    if (!isSame) {
      MessageTip.error('选择的面必须在同一个体上');
      return;
    }
    let result;
    if (props == null) {
      result = await wsApi.createChamfer(getParams(), preview);
    } else {
      result = await wsApi.setParams(props.shape, getParams(), preview);
    }
    previewInCommand(result);
  };
  const previewAction = async () => {
    if (!validataFormData()) {
      previewer.clear();
      return;
    }
    await execute(true);
  };
  return (
    <PickableCommandForm
      isFormDataValid={finishValid}
      onClose={() => {
        previewer.clear();
        onClose();
      }}
      disabled={initingEdit}
      title={title}
      schema={schema}
      formData={formData}
      onChange={setFormData}
      extraUiSchema={{
        'ui:options': {
          classNames: 'command-form command-chamfer',
        },
        pickData: {
          'ui:placeholder': '请输入点/线/面',
          'ui:autofocus': true,
        },
      }}
      submitText='完成'
      onSubmit={checkAndFinishDraw}
    />
  );
}

export const cmdChamfer: BaseCommand = {
  id: 'CmdChamfer',
  label: 'command.chamfer',
  icon: 'commands/feature/chamfer',
  create: (label: string, onClose, props) => (
    <ChamferDialog
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
